 package com.gmrz.uaf.protocol.v1.validaton;
 
 import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.protocol.v1.processor.exception.UAFErrorCode;
import com.gmrz.uaf.protocol.v1.schema.ServerChallenge;
import com.gmrz.uaf.protocol.v1.schema.ServerData;
import com.gmrz.uaf.server.ServerConfig;
import com.google.common.base.Strings;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Arrays;
 
 public class ServerDataValidator
   implements Validator<ServerData>
 {
   private static final Logger LOG = LogManager.getLogger(ServerDataValidator.class);
   private ServerConfig config;
   private Constants.Operation op;
   private ServerChallenge sc;
 
   public ServerDataValidator(ServerConfig config, Constants.Operation op)
   {
     this.config = config;
     this.op = op;
   }
 
   public void validate(ServerData data)
     throws HeaderValidationException
   {
     if (data == null) {
       LOG.error("ServerData is missing, rejecting the response.");
       throw new HeaderValidationException(UAFErrorCode.PROTOCOL_SERVERDATA_VALIDATION_FAILED);
     }
 
     byte opid = data.getOperationId();
     if (this.op.getID() != opid) {
       LOG.error("operationID=[{}] didn't match in Serverdata[{}]", this.op, Byte.valueOf(opid));
       throw new HeaderValidationException(UAFErrorCode.PROTOCOL_SERVERDATA_VALIDATION_FAILED);
     }
 
     String username = data.getUserName();
     LOG.info("username in ServerData[{}]", username);
     if ((this.op.getName().equals(Constants.Operation.REG.getName())) && (Strings.isNullOrEmpty(username))) {
       LOG.error("username must be present in ServerData during Registration");
       throw new HeaderValidationException(UAFErrorCode.PROTOCOL_SERVERDATA_VALIDATION_FAILED);
     }
 
     String policyName = data.getPolicyName();
     LOG.info("policy name in ServerData[{}]", policyName);
     if (Strings.isNullOrEmpty(policyName)) {
       LOG.error("policy must be present in ServerData");
       throw new HeaderValidationException(UAFErrorCode.PROTOCOL_SERVERDATA_VALIDATION_FAILED);
     }
 
     long challenge_ts = data.getTimestamp();
     verifyTimestamp(challenge_ts);
 
     byte[] nonce = data.getChallenge();
     byte[] fcpChallenge = this.sc.getChallenge();
     if ((fcpChallenge == null) || (!Arrays.equals(nonce, fcpChallenge))) {
       LOG.error("Nonce in Server Data didn't match with FCP ServerChallenge nonce");
       throw new HeaderValidationException(UAFErrorCode.PROTOCOL_SERVERDATA_VALIDATION_FAILED);
     }
   }
 
   private void verifyTimestamp(long challenge_ts) throws HeaderValidationException {
     long now = System.currentTimeMillis();
     long expireInterval = this.config.getChallengeValiditySeconds() * 1000L;
     int maxSkew = 5000;
     maxSkew = -1 * maxSkew;
 
     long diff = now - challenge_ts;
     boolean cond = (diff >= maxSkew) && (diff <= expireInterval);
     if (!cond) {
       LOG.error("Timestamp verification failed in ServerData for[" + this.op.getName() + "], current ts=[" + now + "], received ts=[" + challenge_ts + "]");
 
       throw new HeaderValidationException(UAFErrorCode.PROTOCOL_SERVERDATA_VALIDATION_FAILED);
     }
   }
 
   public void setServerChallenge(ServerChallenge sc) {
     this.sc = sc;
   }
 }
